/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ftpcombiner.backup;

import ftpcombiner.ApplicationController;
import ftpcombiner.server.ServerConnection;
import ftpcombiner.server.serverconnection.File;
import ftpcombiner.server.serverconnection.Folder;
import ftpcombiner.server.serverconnection.ServerItem;
import it.sauronsoftware.ftp4j.FTPAbortedException;
import it.sauronsoftware.ftp4j.FTPDataTransferException;
import it.sauronsoftware.ftp4j.FTPException;
import it.sauronsoftware.ftp4j.FTPIllegalReplyException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 *
 * @author Ben
 */
public class TransactionManager {

    private ServerArrayList servers;
    private static TransactionManager instance = null;

    public TransactionManager() {
        servers = new ServerArrayList();
        for (int i = 0; i < ApplicationController.getInstance().getApplicationProperties().getServerProperties().size(); i++) {
            if (!ApplicationController.getInstance().getApplicationProperties().getServerProperties().get(i).getUrl().equals("")) {
                servers.add(new ServerConnection(ApplicationController.getInstance().getApplicationProperties().getServerProperties().get(i).getUrl(), ApplicationController.getInstance().getApplicationProperties().getServerProperties().get(i).getUsername(), ApplicationController.getInstance().getApplicationProperties().getServerProperties().get(i).getPassword()));
                servers.get(i).connectAndLogin();
            }
        }
    }

    public static TransactionManager getInstance() {
        if (instance == null) {
            instance = new TransactionManager();
        }
        return instance;
    }

    public String getCurrentDir() {
        try {
            return servers.get(0).currentDirectory();
        } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
        }
        return "";
    }

    public int getServerCount() {
        return servers.size();
    }

    public ServerArrayList getServers() {
        return servers;
    }

    public static class ServerArrayList extends ArrayList<ServerConnection> {

        public ServerArrayList(int initialCapacity) {
            super(initialCapacity);
        }

        public ServerArrayList() {
            super();
        }

        private void addOrSet(int index, ServerConnection element) {
            try {
                set(index, element);
            } catch (IndexOutOfBoundsException e) {
                add(index, element);
            }
        }
    }

    public void upload(final java.io.File file) {
        for (ServerConnection connection : servers) {
            try {
                if (ApplicationController.getInstance().isBackupMode()) {
                    connection.upload(file);
                } else {
                    connection.upload(file);
                }
                connection.updateCurrentFiles();
                if (!ApplicationController.getInstance().isBackupMode()) {
                    ApplicationController.getInstance().getApplicationFrame().updateFileList();
                }
                break;
            } catch (IllegalStateException | FTPIllegalReplyException | FTPDataTransferException | FTPAbortedException | IOException ex) {
                ApplicationController.getInstance().setAppStatus("Upload Failed");
            } catch (FTPException ex) {
                if (ex.getCode() == 452) {
                } else {
                    ApplicationController.getInstance().setAppStatus("Upload Failed");
                    break;
                }
            }
        }
    }

    /**
     * Downloads a File from the server onto the local computer. This method
     * takes a {@link File} for a parameter instead of a String as in
     * {@link ServerConnection#download}. Also this method and catches
     * exceptions that are thrown by {@linkplain ServerConnection#download}.
     *
     * @param file The {@link File} on the server to download
     * @param localFile The directory on the local computer into which the file
     * should be placed
     *
     * @see ServerConnection#download(java.lang.String, java.io.File,
     * it.sauronsoftware.ftp4j.FTPDataTransferListener)
     */
    public void download(final File file, final java.io.File localFile) {
        ApplicationController.getInstance().setAppStatus("Downloading " + file.getName());
        try {
            file.getServer().download(file.getName(), localFile);
            ApplicationController.getInstance().setAppStatus("Finished downloading " + localFile.getName());
        } catch (IllegalStateException | FTPIllegalReplyException | FTPException | FTPDataTransferException | FTPAbortedException | IOException ex) {
            ApplicationController.getInstance().setAppStatus("Download Failed: " + ex.getMessage());
        }
    }

    public void disconnect() {
        for (ServerConnection server : servers) {
            try {
                server.disconnect(true);
            } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
            }
        }
    }

    public ServerItem[] getCurrentFiles() {
        ServerItem[] arr = {};
        for (ServerConnection server : servers) {
            arr = concat(arr, server.getFiles());
        }
        Set<ServerItem> arrSet = new LinkedHashSet<>(Arrays.asList(arr));
        return arrSet.toArray(new ServerItem[0]);
    }

    private static <T> T[] concat(T[] first, T[] second) {
        T[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    public void changeDirectory(final String dir) {
        for (ServerConnection server : servers) {
            try {
                server.changeDirectory(dir);
                server.updateCurrentFiles();
            } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
                //System.err.println(ex.getMessage());
                ex.printStackTrace();
            }

        }
    }

    public void changeDirectoryUp() {
        for (ServerConnection server : servers) {
            try {
                server.changeDirectoryUp();
                server.updateCurrentFiles();
            } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
                System.err.println(ex.getMessage());
            }

        }
    }

    public void createDirectory(String name) {
        for (ServerConnection server : servers) {
            try {
                server.createDirectory(name);
                server.updateCurrentFiles();
            } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
                System.err.println("Servers not formatted correctly: " + ex.getMessage());
            }
        }
    }

    public void delete(File file) {
        try {
            file.getServer().deleteFile(file.getName());
            file.getServer().updateCurrentFiles();
            //System.out.println("Delete");
        } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
        }
    }

    public void deleteDirectory(Folder folder) {
        try {
            for (ServerConnection server : servers) {
                server.deleteDirectory(folder.getName());
            }
        } catch (IllegalStateException | IOException | FTPIllegalReplyException | FTPException ex) {
            System.err.println("Delete Folder failed");
        }
    }
}
